package com;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import com.bean.LoginSuccessBean;
import com.constant.Constant;
import com.event.DisconnectEvent;
import com.google.gson.JsonSyntaxException;
import com.interfaces.IEvent;
import com.lottery.R;
import com.message.MsgHead;
import com.message.MsgId;
import com.message.MsgPacket;
import com.message.RecBufferQueue;
import com.message.SendBufferQueue;
import com.message.UserClient;
import com.util.JsonUtils;
import com.util.LogUtil;
import com.util.NetworkUtil;
import com.util.ToastUtils;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * Created by Mars on 2017/9/21.
 * 类似于HairdressingService
 */

public class LotteryService extends Service {

    private NetWorkChangeReceiver netWorkChangeReceiver;
    private UserClient mUserClient;
    private RecBufferQueue mRecMsgQueue;
    private SendBufferQueue<Object> mSendMsgQueue;

    private boolean mbThreadRunning = false;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //super.handleMessage(msg);

            LogUtil.e("mHandler-handleMessage: " + msg.toString());

            switch (msg.what) {
                case MsgId.MSG_CLIENT_CALLBACK_HANDLER:
                    mClientMessenger = msg.replyTo;//get the messenger of client
                    break;
                case MsgId.MSG_CLIENT_REQUEST:
                    processSendRequest((short) msg.arg1, (String) msg.obj);
                    break;
                case MsgId.MSG_CLIENT_DISCONNECT:
                    mSendMsgQueue.clear();
                    disconnect();
                    break;
                case MsgId.MSG_CLIENT_RECONNECT:
                    if (mUserClient != null) {
                        mUserClient.connect();
                    }
                    break;
                default:
                    break;
            }
        }

    };

    private Messenger mMessenger = new Messenger(this.mHandler);
    private Messenger mClientMessenger = null;

    /**
     * 线程：事件分发
     */
    private Thread mMsgSendThread = new Thread(new Runnable() {
        @Override
        public void run() {
            mbThreadRunning = true;

            while (mbThreadRunning) {
                if (mSendMsgQueue.size() > 0) {
                    if (mUserClient.isConnected() && !mUserClient.isStateConnecting()) {
                        LogUtil.e("mMsgSendThread.run-connect");
                        mUserClient.connect();
                    }
                    if (mUserClient.isConnected() && !mUserClient.isStateLoggingIn()) {
                        MsgPacket mp = (MsgPacket) mSendMsgQueue.pop();
                        mUserClient.sendRequest(mp);
                    } else if (!mUserClient.isStateConnecting()) {
                        mSendMsgQueue.clear();
                        DisconnectEvent event = new DisconnectEvent();
                        sendEventToClient(MsgId.MSG_CLIENT_RECONNECT, event);
                    }

                }
            }
        }
    });


    @Override
    public void onCreate() {
        super.onCreate();

        registerNetWorkChangeReceiver();

        mUserClient = new UserClient(Constant.IP, Constant.PORT);
        mUserClient.init(new TimeClientHandler());

        if (mRecMsgQueue == null)
            mRecMsgQueue = new RecBufferQueue(UserClient.MAX_READ_BUFFER_SIZE);
        if (mSendMsgQueue == null)
            mSendMsgQueue = new SendBufferQueue<>();

        mMsgSendThread.start();

    }


    private void processSendRequest(short usMsgType, String sBody) {
        //CommonUtils.LogI("HairdressingService", "processSendRequest-state:" + mUserClient.getState());

        //判断是否登录或正在登录，且是不是不用登录就能操作的id
//        if (!mUserClient.isStateLoggingIn()
//                && !mUserClient.isStateLoggedIn()) {
//            MsgPacket mp = new MsgPacket(usMsgType);
//            mp.mMsgType = MsgId.MSG_LOGIN;
//            // TODO: 2017/10/18 先return掉再解决
//            return;
//        }

        MsgPacket mp = new MsgPacket(usMsgType);
        mp.mMsgType = usMsgType;
        mp.setBody(sBody);

        mSendMsgQueue.push(mp);
        LogUtil.e("----");
    }

    private class TimeClientHandler extends IoHandlerAdapter {

        public TimeClientHandler() {
        }

        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            LogUtil.e("-- exceptionCaught");
        }

        @Override
        public void sessionCreated(IoSession session) throws Exception {
            LogUtil.e("-- sessionCreated");
        }

        @Override
        public void sessionOpened(IoSession session) throws Exception {
            LogUtil.e("-- sessionOpened");
        }

        @Override
        public void sessionClosed(IoSession session) throws Exception {
            LogUtil.e("-- sessionClosed");
            mSendMsgQueue.clear();
            disconnect();
        }

        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
            LogUtil.e("-- sessionClosed");
            if (status == IdleStatus.READER_IDLE) {
                mSendMsgQueue.clear();
                disconnect();
            }
        }

        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {
            LogUtil.e("messageReceived: " + message.toString());

            MsgPacket mp = (MsgPacket) message;
            byte bA[] = mp.array();

            mRecMsgQueue.put(bA, bA.length);

            while (true) {
                byte bb[] = mRecMsgQueue.pop();

                if (bb == null) {
                    break;
                }
                // TODO: 2017/9/26 event事件
                parse(bb);

            }
        }
    }

    private void parse(byte[] bA) {
        if (bA == null || bA.length < MsgHead.HEAD_SIZE)
            return;
        ByteBuffer bb = ByteBuffer.allocateDirect(bA.length);
        bb.order(ByteOrder.nativeOrder());
        bb.put(bA);
        bb.position(0);

        // TODO: 2017/9/26 数据解析
//        byte[] name = new byte[2];
        short packageSize = bb.getShort();
        short packageInstruction = bb.getShort();
        short ucMsgType = bb.getShort();
        short packageOrderNum = bb.getShort();

        String sJson = null;
        Object obj = null;
        Class<?> cls;

        int ucBodyLen = packageSize - 8;

        if (ucBodyLen < 0) {
            ucBodyLen = (ucBodyLen & Short.MAX_VALUE) + Short.MAX_VALUE + 1;
        }

        if (ucBodyLen > 0) {
            byte ba[] = new byte[ucBodyLen];
            bb.get(ba);
            sJson = new String(ba);
        }

        switch (ucMsgType) {
            case MsgId.MSG_LOGIN:
                cls = LoginSuccessBean.class;
                obj = jsonParse(ucBodyLen, sJson, cls);
                break;
            case MsgId.MSG_GET_ALL_LIST:
                LogUtil.e("Body = " + sJson);
                break;
        }

        IEvent ie = (IEvent) obj;

        if (ie != null) {
            sendEventToClient(ucMsgType, ie);
        }

    }

    private <T> T jsonParse(int bodyLen, String sJson, Class<T> cls) {
        T ie;

        if (bodyLen != 0 && sJson != null && sJson.length() > 0) {
            try {
                ie = JsonUtils.getResult(sJson, cls);
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                return null;
            }
        } else {
            return null; //Wrong
        }
        return ie;
    }

    private void registerNetWorkChangeReceiver() {
        netWorkChangeReceiver = new NetWorkChangeReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        registerReceiver(netWorkChangeReceiver, filter);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        LogUtil.e("onBind");
        return mMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        mClientMessenger = null;
        disconnect();
        return true;
    }

    private void disconnect() {
        if (mUserClient.isStateConnected()
                || mUserClient.isStateConnecting()
                || mUserClient.isStateLoggingIn()
                || mUserClient.isStateLoggedIn()
                || mUserClient.isConnected()) {
            mUserClient.disconnect();

            DisconnectEvent event = new DisconnectEvent();
            sendEventToClient(MsgId.MSG_CLIENT_DISCONNECT, event);
        }
    }

    private boolean sendEventToClient(short usMsgType, IEvent ie) {
        Message msg = new Message();
        msg.what = usMsgType;
        msg.obj = ie;

        try {
            LogUtil.e("sendEventToClient-usMsgType=" + usMsgType);
            if (mClientMessenger != null) {
                mClientMessenger.send(msg);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    @Override
    public void onDestroy() {
        stopThread();
        unregisterReceiver(netWorkChangeReceiver);
        super.onDestroy();
    }

    public void stopThread() {
        mbThreadRunning = false;
    }

    class NetWorkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (!NetworkUtil.isNetworkAvailable()) {
                ToastUtils.showToast(MyApp.getInstance().getString(R.string.network_unable));
            }
        }
    }

}
